package com.open.basic.util;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author: system
 * @Date: 2024/9/24 上午10:31
 * @Version: V1.0
 * @description: -> 反射工具类
 */

public class ReflectionUtils<R> {

    private static final Map<Class<?>, Method[]> METHODS_CACHE_MAP = new ConcurrentHashMap<>();

    private static final String GET_METHOD_PREFIX = "get";

    private static final String SET_METHOD_PREFIX = "set";

    private ReflectionUtils() {}

    public static <T> T newInstance(Class<T> clazz) {
        try {
            // 无参构造
            return clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // public static void loadClass(String classFullName) throws ClassNotFoundException{
    //     Class.forName(classFullName);
    // }

    public static Object invokeGetterMethod(Object obj, String propertyName) {
        String getterMethodName = GET_METHOD_PREFIX + StringUtils.capitalize(propertyName);
        return invokeMethod(obj, getterMethodName, (Class[])null, (Object[])null);
    }



    public static void invokeSetterMethod(Object obj, String propertyName, Object value) {
        invokeSetterMethod(obj, propertyName, value, (Class)null);
    }

    public static void invokeSetterMethod(Object obj, String propertyName, Object value, Class<?> propertyType) {
        propertyType = null != propertyType ? propertyType : value.getClass();
        String setterMethodName = SET_METHOD_PREFIX + StringUtils.capitalize(propertyName);
        invokeMethod(obj, setterMethodName, new Class[]{propertyType}, new Object[]{value});
    }

    public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, final Object[] args) {
        Method method = obtainAccessibleMethod(obj, methodName, parameterTypes);
        if (null == method) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "].");
        } else {
            try {
                return method.invoke(obj, args);
            } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 获取可访问方法
     * @param obj
     * @param methodName
     * @param parameterTypes
     * @return
     */
    public static Method obtainAccessibleMethod(final Object obj, final String methodName, final Class<?>... parameterTypes) {
        Class<?> superClass = obj.getClass();
        Class<Object> objClass = Object.class;

        while(superClass != objClass) {
            Method method = null;

            try {
                method = superClass.getDeclaredMethod(methodName, parameterTypes);
                method.setAccessible(true);
                return method;
            } catch (SecurityException | NoSuchMethodException var7) {
                superClass = superClass.getSuperclass();
            }
        }

        return null;
    }

    public static Method obtainMethod(final Object obj, final String methodName) {
        Class<?> clazz = obj.getClass();
        Method[] methods = (Method[])METHODS_CACHE_MAP.get(clazz);
        if (null == methods) {
            methods = clazz.getDeclaredMethods();
            METHODS_CACHE_MAP.put(clazz, methods);
        }

        int var5 = methods.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            Method method = methods[var6];
            if (method.getName().equals(methodName)) {
                return method;
            }
        }

        return null;
    }




}
